﻿#region Copyright (C) Sector7 Software Studio. All rights reserved
/*******************************************************************************************
 * Creation
 *      Author:         Wolf Lai
 *      Date:           2013/2/18 星期一 23:43:32
 *      Version:        
 * Modification 
 *      Author: 
 *      Date: 
 *      Description: 
 *      Version:
 *******************************************************************************************/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using Sector7.Framework.Core;
using Sector7.Framework.Consts;
using Sector7.Framework.Utility;
using Sector7.Framework.Enums;

namespace Sector7.Framework.DB
{
    /// <summary>
    /// 数据访问对象基类
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    public class DAOBase<T> : IDAOBase<T> where T : class, new()
    {
        #region Accessor
        #endregion

        #region Public functions
        public virtual object Create(T entity)
        {
            string sql = @"
                INSERT INTO {0}
                        ({1})
                    VALUES
                        ({2})
                {3}";

            string keyStatement = string.Empty;
            string valueStatement = string.Empty;
            string returnStatement = string.Empty;

            var properties = ReflectionUtil.GetProperties(entity, typeof(DBFieldAttribute));
            var paramList = new List<SqlParameter>();
            foreach (var property in properties)
            {
                var attribute = ReflectionUtil.GetPropertyAttribute<DBFieldAttribute>(property);
                if (attribute.DBFieldType == DBFieldType.PrimaryKey && attribute.DBKeyType == DBKeyType.Automatic)
                {
                    returnStatement = "SELECT @@IDENTITY";
                }
                else
                {
                    var propertyName = property.Name;
                    keyStatement += string.Format("{0},", propertyName);
                    valueStatement += string.Format("@{0},", propertyName);
                    paramList.Add(DBUtil.CreateSqlParameter(property.GetValue(entity, null), propertyName));
                }
            }

            if (keyStatement.Length > 0)
            {
                keyStatement = keyStatement.Remove(keyStatement.Length - 1);
                valueStatement = valueStatement.Remove(valueStatement.Length - 1);
            }

            sql = string.Format(sql, typeof(T).Name, keyStatement, valueStatement, returnStatement);

            using (DBHelper helper = new DBHelper())
            {
                return helper.ExecuteScalar(sql, paramList.ToArray());
            }
        }

        public virtual int CreateAll(List<T> entityList)
        {
            string sql = @"
                INSERT INTO {0}
                        ({1})
                    VALUES
                        ({2})
                {3}";

            string keyStatement = string.Empty;
            string valueStatement = string.Empty;
            string returnStatement = string.Empty;

            var entityType = typeof(T);

            var properties = ReflectionUtil.GetProperties(entityType, typeof(DBFieldAttribute));
            var columnList = new List<string>();
            foreach (var property in properties)
            {
                var attribute = ReflectionUtil.GetPropertyAttribute<DBFieldAttribute>(property);
                if (attribute.DBFieldType != DBFieldType.PrimaryKey || attribute.DBKeyType != DBKeyType.Automatic)
                {
                    var propertyName = property.Name;
                    keyStatement += string.Format("{0},", propertyName);
                    valueStatement += string.Format("@{0},", propertyName);
                    columnList.Add(propertyName);
                }
            }

            if (keyStatement.Length > 0)
            {
                keyStatement = keyStatement.Remove(keyStatement.Length - 1);
                valueStatement = valueStatement.Remove(valueStatement.Length - 1);
            }

            sql = string.Format(sql, entityType.Name, keyStatement, valueStatement, returnStatement);

            using (DBHelper helper = new DBHelper())
            {
                return helper.ExecuteBatchNonQuery(sql, entityList, columnList.ToArray());
            }
        }

        public virtual T Read(object primaryKey)
        {
            throw new NotImplementedException();
        }

        public virtual List<T> ReadAll()
        {
            string sql = string.Format(@"
                SELECT *
                    FROM {0}", m_tableName);

            using (DBHelper helper = new DBHelper())
            {
                SqlDataReader reader = helper.ExecuteQuery(sql);
                List<T> entityList = new List<T>();

                while (reader.Read())
                {
                    object entity = new T();
                    DBUtil.ReadData(reader, entity);

                    entityList.Add(entity as T);
                }

                return entityList;
            }
        }

        public virtual int Update(EntityDeltaBase delta)
        {
            using (DBHelper opt = new DBHelper())
            {
                return opt.ExecuteNonQuery(
                    DBUtil.CreateUpdateSql(delta),
                    DBUtil.CreateUpdateParameters(delta));
            }
        }

        public virtual int Delete(object primaryKey)
        {
            string sql = string.Format("DELETE FROM {0} WHERE {1} = @{1}",
                m_tableName, m_primaryKeyName);

            using (DBHelper helper = new DBHelper())
            {
                return helper.ExecuteNonQuery(sql,
                    DBUtil.CreateSqlParameter(primaryKey, m_primaryKeyName));
            }
        }
        #endregion

        #region Private functions
        #endregion

        #region Structure
        public DAOBase()
        {
            m_tableName = typeof(T).Name;

            switch (m_tableName)
            {
                case C_TableName.DATA_ELEMENT:
                    m_primaryKeyName = C_PrimaryKeyName.DATA_ELEMENT;
                    break;
                case C_TableName.DATA_GROUP:
                    m_primaryKeyName = C_PrimaryKeyName.DATA_GROUP;
                    break;
                case C_TableName.DATA_TEMPLATE:
                    m_primaryKeyName = C_PrimaryKeyName.DATA_TEMPLATE;
                    break;
                case C_TableName.DATA_TEMPLATE_ITEM:
                    m_primaryKeyName = C_PrimaryKeyName.DATA_TEMPLATE_ITEM;
                    break;
                case C_TableName.METADATA:
                    m_primaryKeyName = C_PrimaryKeyName.METADATA;
                    break;
                case C_TableName.VALUE_DOMAIN:
                    m_primaryKeyName = C_PrimaryKeyName.VALUE_DOMAIN;
                    break;
                case C_TableName.VALUE_DOMAIN_ITEM:
                    m_primaryKeyName = C_PrimaryKeyName.VALUE_DOMAIN_ITEM;
                    break;
                case C_TableName.VALUE_TYPE:
                    m_primaryKeyName = C_PrimaryKeyName.VALUE_TYPE;
                    break;
                default:
                    break;
            }
        }
        #endregion

        #region Inner members
        protected string m_tableName;
        protected string m_primaryKeyName;
        #endregion
    }
}
